{***************************************************************
    SpyGestion  Copyright (C) 2008 Christophe KOALI <nature2gas@gmail.com>
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    
****************************************************************}
unit modFlotteTracking;

interface

uses modFlotteVaisseauxChoix, modBaseDeDonnesRapport,
     modBaseType,
     Classes,
     SysUtils,
     modApercuMsg,
     modAlarmeAttaque,
     modFlotteEnVoyage,

     sFonctionsChaines;




    // suivi de ses propores flottes pour pouvoir sonder avant l'inmpact
    // ET
    // pour pouvoir rappeller une flotte qui a été utilisé pour l'évacuation


type


    TOwnFlotteTracking = record
        // Combine l'impact serveur et la planete de depart/arrive
        // calcule avec alarmGetUID
        // Ce N'EST PAS et ce NE DOIT PAS être un uid aléatoire ou séquentiel
        uid      : TFlotteOwnUID;

        Depart   : TPlanetLocation;
        Arrivee  : TPlanetLocation;

        ArriveeDateServeur: int64;
        ArriveeDateLocal  : int64;


        Direction: TOGDirection;

        // Informations sur les vaisseaux et ce qu'ils transportent
        Nombre   : integer;
        Vaisseaux: string;


        // Dans le sens ALLER, la date de retour correspond à la date d'impact
        // Dans le sens RETOUR, la date correspond à la date de retour
        //DateImpactServeur: int64;
        //DateImpactLocal  : int64;


        // Status pour le sondage avant impact
        SondageAvantImpact: integer;

        // date à laquelle on doit sonder (si on doit le faire, sinon = 0)
        SondageDateToDo   : int64;

        
        // Définit si c'est une flotte d'évacuation
        EvacuationState   : integer;
        EvacuationFlags   : longword;
        EvacuationAlerteAttIndex: integer;

        // Définit la date à laquelle le robot doit cliquer sur "Retour"
        // C'est une fonction d'évacuation, mais l'humain peut souhaiter la faire retourner
        DateToMakeReturn: int64;


        // pour déterminer si la flotte est retournée a quai (ou stationnée, ou a été détruite)
        FlotteExistePlus: boolean;
        FlotteDateNexistePlus: int64;     // (date local du pc)
    end;


    POwnFlotteTracking = ^TOwnFlotteTracking;
    TCollectionOwnFlotteTracking = class(TList)
    private
       {--------------------------------------------------}
       {Elements spécialisés de la classes}

       // Dernière flotte ajoutée
       FLastFlotteAdded: POwnFlotteTracking;


       {--------------------------------------------------}
       {Gestion des pointeurs}
       // Utilisé pour la propriété Itemx
       function GetItemx(Index: integer): TOwnFlotteTracking;

       procedure SetFlagFlotteExistePlus;

       function AddFromFlotteList(peFlotte: PFlotteListEnVoyage): POwnFlotteTracking;

    public
       DiffHeureLocaleHeureServeur: int64;

       LastDateUpdated: int64;


       property LastFlotteAdded: POwnFlotteTracking read FLastFlotteAdded;
       
       {--------------------------------------------------}
       {Gestion des pointeurs}
       // *** Ajout de pointeurs
       // Renvoi le pointeur de l'élément ajouté
       function Add(Element: TOwnFlotteTracking): POwnFlotteTracking;
      
       // Simple ajout de pointeur
       procedure SimpleAdd(Pointeur: POwnFlotteTracking);
      
       // Renvoi le pointeur de l'élément ajouté/modifié
       // Utilise Get_Index pour vérifier si l'élément doit être mis à jour
       function Add_Update(Element: TOwnFlotteTracking): POwnFlotteTracking;
      
      
       // *** Suppression de pointeur
       // Libère et supprime le pointeur Index
       // Renvoi True si réussit, False si hors limite ou erreur
       function Delete(Index: integer): boolean; 

      
       // *** Effacement de la liste de pointeur
       procedure Clear; override;
      
      
       // *** Requete sur la liste de pointeur
       function Get_Index(Element: PFlotteOwnUID): integer;
       function Get_Pointeur(Element: PFlotteOwnUID): POwnFlotteTracking;
       function Get_Item(Index: integer): TOwnFlotteTracking;
       property Itemx[Index: integer]: TOwnFlotteTracking read GetItemx;
      

       // Renvoi le nombre de flotte ajouté
       function RefreshFromFlottePage(flottes: TCollectionFlotteListEnVoyage): integer;


       {--------------------------------------------------}
       {Procédures et fonctions spécialisées de la classes}
       // Destructeur
       destructor Destroy; override;
       constructor Create;


    end;


implementation

uses ESBDates;

function mftCompareUIDAreEgal(u1, u2: PFlotteOwnUID): boolean;
begin
    Result := False;
    if u1.DateDepart = u2.DateDepart then begin
       if u1.Location = u1.Location then begin
          Result := true;
       end;
    end;
end;


{*******************************************************************************
 ******************************************************************************* 
 **               TCollectionOwnFlotteTracking                                     **
 *******************************************************************************
 *******************************************************************************}

procedure TCollectionOwnFlotteTracking.SetFlagFlotteExistePlus;
var i: integer;
    pElement: POwnFlotteTracking;
begin

   if Count <= 0 then exit;

   for i := 0 to Count - 1 do begin
      pElement := Items[i];
      pElement.FlotteExistePlus := true;
   end;

end;

function TCollectionOwnFlotteTracking.AddFromFlotteList(peFlotte: PFlotteListEnVoyage): POwnFlotteTracking;
var Element: TOwnFlotteTracking;
begin

   Element.uid.Location   := peFlotte.HashDepartArrivee;
   Element.uid.DateDepart := peFlotte.DepartDate;

   Element.Depart         := peFlotte.Depart;
   Element.Arrivee        := peFlotte.Arrivee;

   Element.Direction      := peFlotte.Direction;

   Element.Nombre         := peFlotte.Nombre;
   Element.Vaisseaux      := peFlotte.Vaisseaux;

   // heure du serveur
   Element.ArriveeDateServeur := peFlotte.ArriveeDate;
   Element.ArriveeDateLocal   := peFlotte.ArriveeDate + DiffHeureLocaleHeureServeur;


        // Status pour le sondage avant impact
        Element.SondageAvantImpact := 0;
        Element.SondageDateToDo    := 0;

        // Définit si c'est une flotte d'évacuation
        Element.EvacuationState   := 0;
        Element.EvacuationFlags   := 0;
        Element.EvacuationAlerteAttIndex:= -1;

        Element.DateToMakeReturn := 0;


        // pour déterminer si la flotte est retournée a quai (ou stationnée, ou a été détruite)
        Element.FlotteExistePlus      := false;
        Element.FlotteDateNexistePlus := 0;


   Result := Add(Element);


end;

function TCollectionOwnFlotteTracking.RefreshFromFlottePage(flottes: TCollectionFlotteListEnVoyage): integer;
var i: integer;
    pe: POwnFlotteTracking;
    peFlotte: PFlotteListEnVoyage;
    peFlotteUID: TFlotteOwnUID;
begin

    FLastFlotteAdded := nil;
    SetFlagFlotteExistePlus;
    Result := 0;

    if flottes.Count = 0 then begin
       // plus de flotte
       exit;
    end;

    for i := 0 to flottes.Count - 1 do begin
       peFlotte := flottes.Items[i];

       peFlotteUID.Location   := peFlotte.HashDepartArrivee;
       peFlotteUID.DateDepart := peFlotte.DepartDate;

       pe := Get_Pointeur(@peFlotteUID);

       if pe = nil then begin
          // nouvelle flotte

          FLastFlotteAdded := AddFromFlotteList(peFlotte);
          Inc(Result);

       end else begin
          // flotte déjà existante
          // met à jour les champs qui peuvent changer
          pe.Direction := peFlotte.Direction;

          pe.ArriveeDateServeur := peFlotte.ArriveeDate;
          pe.ArriveeDateLocal   := peFlotte.ArriveeDate + DiffHeureLocaleHeureServeur;

          // la flotte existe encore, on lui enlève le flag
          pe.FlotteExistePlus   := false;
       end;

    end;


    for i := 0 to Count - 1 do begin
       pe := Items[i];

       if pe.FlotteExistePlus then begin
          if pe.FlotteDateNexistePlus < 100 then begin
             pe.FlotteDateNexistePlus := DateTimeToUnix(Now);
          end;
       end;
    end;

end;

constructor TCollectionOwnFlotteTracking.Create;
begin
    
    // Héritage
    InHerited Create;
    
    
    
    // Code pour l'initialisation ici
    FLastFlotteAdded := nil;

    LastDateUpdated := 0;
end;

destructor TCollectionOwnFlotteTracking.Destroy;
begin
    // Implémenter le code avant l'héritage de la méthode
    // C'est à dire ici
    
   
    // On appelle NOTRE clear qui lui-même appelle NOTRE Delete qui libère l'espace mémoire
    // avant d'enlever le pointeur de la TList
    // L'héritage de Destroy appelle Clear, mais es-ce le notre ou celui de la classe de base ?
    Clear;
    
    
    // Héritage
    InHerited Destroy;
end;


procedure TCollectionOwnFlotteTracking.Clear;
var i: integer;
begin

    if Count > 0 then begin
        For i := Count -1 downto 0 do
            Delete(i);
    end;
    
    inherited Clear;
end;


function TCollectionOwnFlotteTracking.Get_Pointeur(Element: PFlotteOwnUID): POwnFlotteTracking;
var i: integer;
begin

   Result := nil;
   
   i := Get_Index(Element);
   if i < 0 then exit;
   Result := Items[i];

end;


function TCollectionOwnFlotteTracking.Get_Index(Element: PFlotteOwnUID): integer;
var i: integer;
    pElement: POwnFlotteTracking;
begin

   Result := -1;

   if Count <= 0 then exit;

   for i := 0 to Count - 1 do begin
      pElement := Items[i];

      {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
      {### Neccessite adpation en fonction du type record  ### }
      {### ### ### ### ### ### ### ### ### ### ### ### ### ### }

      if mftCompareUIDAreEgal(@(pElement.uid), Element) then begin
         Result := i;
         exit;
      end;
   end;

end;



function TCollectionOwnFlotteTracking.Add_Update(Element: TOwnFlotteTracking): POwnFlotteTracking;
var i : integer;
begin
     
     Result := nil;
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     i := Get_Index(@Element.uid);        {### Neccessite adpation en fonction du type record  ### }
                                         {### ### ### ### ### ### ### ### ### ### ### ### ### ### }
     if i < 0 then begin 
        // L'élément n'existe pas, l'ajoute
        Result  := Add(Element);
     end else begin
        // L'élément existe déjà, le met à jour
        Result  := Items[i];     // Obtient le pointeur
        Result^ := Element;
     end;
     
end;




function TCollectionOwnFlotteTracking.Get_Item(Index: integer): TOwnFlotteTracking;
var pElement: POwnFlotteTracking;
begin

     if Index < 0 then exit;
     if Index >= Count then exit;

     pElement := Items[Index];     // Obtient le pointeur
     Result := pElement^;

end;

function TCollectionOwnFlotteTracking.Delete(Index: integer): boolean;
var pElement: POwnFlotteTracking;
begin

    Result := false;

    if (Index < 0) or (Index >= Count) then
       // Hors limite
       exit;


    // Obtient le pointeur
    pElement := Items[Index];

    if pElement <> nil then
       // Libére la mémoire créée lors de l'ajout
       Dispose(pElement);

    // Supprime le pointeur de la liste
    inherited Delete(Index);

    // Met le resultat à True
    Result := true;

end;



function TCollectionOwnFlotteTracking.Add(Element: TOwnFlotteTracking): POwnFlotteTracking;
var pElement: POwnFlotteTracking;
begin
    
    Result := nil;
    
    New(pElement);          // Créer l'espace mémoire requis
    pElement^ := Element;   // Recopie les données dans l'emplacement pointé
    
    try
       inherited Add(pElement);  // Ajoute le pointeur à la liste
       Result := pElement;
    except
       Result := nil;
    end;
    
    // Pour libérer la mémoire occupé par l'élément pointer:  Dispose(pElement);

end;

// Simple ajout de pointeur
procedure TCollectionOwnFlotteTracking.SimpleAdd(Pointeur: POwnFlotteTracking);
begin
    
    inherited Add(Pointeur);  // Ajoute le pointeur à la liste
    
end;

function TCollectionOwnFlotteTracking.GetItemx(Index: integer): TOwnFlotteTracking;
var pElement: POwnFlotteTracking;
begin

   if Count < 0 then exit;
   if Index >= Count then exit;

   pElement := Items[Index];
   Result := pElement^;

end;


end.
